import { EventManager } from "../Managers/EventManager";
import { Loader } from "../Loader/Loader";
import { ModuleManager } from "../Managers/ModuleManager";
import { Assets } from "./Assets";
import { ModuleEvent } from "../Event/ModuleEvent";
import { FModule } from "./FModule";
import { IModule } from "../Interfaces/IModule";
import { MediatorManager } from "../Managers/MediatorManager";
import { IDispose } from "../Interfaces/IDispose";
import { FEvent } from "../Event/FEvent";
import { getQualifiedClassName } from "../Utility/dx/getQualifiedClassName";
/**
 * 启动Mediator需要
 * 1.先调用startMediator(); 初始化所有模块，并获取到需要预加载的素材
 * 2.调用 initialize(); 完成Mediator自身的初始化
 */
export class FMediator
{
    /**对应的场景名称 */
    public sceneName:string = "";
    public mediatorName:string = "";
    /**是否已经初始化模块**/
    protected isInitModules: boolean = false;
    protected modules:{[key:string]:IModule} = {};
    protected moduleEvents: { [key: string]: Array<IModule> };
    protected disObjects:IDispose[] = [];

    public constructor()
    {
        MediatorManager.AddMediator(this);
        this.mediatorName = getQualifiedClassName(this);
    }

    public startMediator():void
    {
        this.initModules();
    }

    /**预加载的素材 */
    public preloadAssets():Loader
    {
        let assets = [];
        for (let key in this.modules) 
        {
            if(this.modules[key].isNeedPreload)
                assets = assets.concat(this.modules[key].assets);
        }
        let loader:Loader = Loader.Get();
        loader.loads(Assets.GetAssets(assets));
        return loader;
    }
    public initialize(): void
    {
        if(this.isInitModules)return;
        MediatorManager.SetCurrentMediator(this);
        this.isInitModules = true;
        this.showModules();
        this.addEvents();            
    }
    /**初始化模块 */
    protected initModules(): void 
    {
    }

    public addModule(moduleName: string, moduleData: typeof FModule|IModule,...events): IModule
    {
        if(typeof moduleData==="function")
        {
            if (!ModuleManager.instance.hasModule(moduleName))
                ModuleManager.instance.addModuleClass(moduleName, moduleData, true);
        }else if(typeof moduleData==="object")
        {
            ModuleManager.instance.addModule(moduleData,moduleName);
            // ModuleManager.instance.addModule(moduleData,moduleName,this.mediatorName);
        }
        let m: IModule = ModuleManager.instance.getModule(moduleName);
        // let m: IModule = ModuleManager.instance.getModule(moduleName,this.mediatorName);
        this.modules[moduleName] = m;
        m.moduleName = moduleName;
        this.addModuleEvent(m,events);
        return m;
    }


    public addModuleEvent(m:IModule,events:string[]):void
    {
        if(this.moduleEvents ==null) this.moduleEvents = {};
        for (let i = 0; i < events.length; i++)
        {
            if (this.moduleEvents[events[i]] == null)
                this.moduleEvents[events[i]] = [];
            if (this.moduleEvents[events[i]].indexOf(m) == -1)
                this.moduleEvents[events[i]].push(m);
        }
    }

    public showModules(): void
    {
        
    }
    protected addEvents(): void
    {
        EventManager.addEvent(this,"OnDisposeModuleObject",this.onDisposeModuleObject);
    }
    protected removeEvents(): void 
    {
        EventManager.removeEvent(this);
    }
    protected removeModules(): void 
    {
        for(let key in this.modules)
        {
            //EventManager.dispatchEvent(new ModuleEvent(ModuleEvent.DISPOSE_MODULE,key,this.mediatorName));
            EventManager.dispatchModuleEventWith(ModuleEvent.DISPOSE_MODULE,key);
            delete this.modules[key];
        }
    }
    protected excuteModuleEvent(eventName: string, funName: string, ...args): void 
    {
        if(!this.moduleEvents)return;
        let modules = this.moduleEvents[eventName];
        if (modules != null) 
        {
            args.unshift(funName);
            for (let i = 0; i < modules.length; i++) 
            {
                let fun: Function = modules[i].excuteModuleFun;
                if (fun != null) fun.apply(modules[i], args);
            }
        }
    }

    private onDisposeModuleObject(evt:FEvent):void
    {
        let m:IModule = evt.data;
        if(m==null)return;
        if(!this.modules[m.moduleName])return;
        for(let eventName in this.moduleEvents)
        {
            let index = this.moduleEvents[eventName].indexOf(m);
            if(index!=-1)this.moduleEvents[eventName].splice(index,1);
        }
        delete this.modules[m.moduleName];
    }
    public dispose(): void 
    {
        MediatorManager.RemoveMediator(this);
        if(MediatorManager.GetMediator()==this)
            MediatorManager.SetCurrentMediator(null);
        this.moduleEvents = null;
        this.removeEvents();
        this.removeModules();
        this.disposeObjects();
    }

    protected addObject(obj:IDispose):void
    {
        if(this.disObjects.indexOf(obj)==-1)
            this.disObjects.push(obj);
    }
    protected disposeObjects():void
    {
        while(this.disObjects.length>0)
        {
            this.disObjects.shift().dispose();
        }
    }
}
